import 'navigator.dart';
import 'package:flutter/material.dart';

class PageNavigator extends StatefulWidget {
  final String _mainTab;
  final GlobalKey _navigatorKey;
  final RouteFactory _pageRoutes;
  final List<NavigatorObserver> _navigatorObservers;
  final PageNavigatorState _state;

  PageNavigator({
    Key key,
    String mainTab,
    GlobalKey navigatorKey,
    List<NavigatorObserver> navigatorObservers = const <NavigatorObserver>[],
    @required RouteFactory pageRoutes,
  })  : assert(pageRoutes != null),
        _mainTab = mainTab,
        _pageRoutes = pageRoutes,
        _navigatorObservers = navigatorObservers,
        _navigatorKey = navigatorKey,
        _state = _PageNavigatorStateWithoutBinding(),
        super(key: key);

  @override
  PageNavigatorState createState() => _state;

  /// Method that allows widgets to access the page navigator instances as
  /// long as their `BuildContext` contains a [PageNavigator] instance.
  static PageNavigatorState of(
    BuildContext context, {
    bool nullOk = false,
  }) {
    try {
      return Provider.of<PageNavigatorState>(context, listen: false);
    } on Object catch (_) {
      // Same behavior as `Navigator.of`
      assert(() {
        if (!nullOk) {
          throw FlutterError(
            """
            PageNavigator.of() called with a context that does not contain a PageNavigator.
            No ancestor could be found starting from the context that was passed to PageNavigator.of().

            This can happen if the context you used comes from a widget above the PageNavigator.

            The context used was: $context
            """,
          );
        }
        return true;
      }());
      return null;
    }
  }
}

abstract class PageNavigatorState extends State<PageNavigator> {
  final _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    print('PageNavigatorState build ${widget._mainTab}');
    return _PageNavigatorProvider(
      pageNavigatorState: this,
      child: WillPopScope(
        onWillPop: _handleWillPop,
        child: widget._navigatorKey.currentWidget ??
            Navigator(
              key: widget._navigatorKey ?? _navigatorKey,
              initialRoute: '/',
              onGenerateRoute: _onGenerateRoute,
              observers: widget._navigatorObservers,
            ),
      ),
    );
  }

  RouteFactory get _onGenerateRoute;

  Future<bool> _handleWillPop() async {
    final navigatorState = _navigatorKey.currentState;
    if (navigatorState == null) {
      return true;
    } else {
      final didPop = await navigatorState.maybePop();
      return !didPop;
    }
  }

  /// Parent navigator instance.
  /// It provides a page navigation pattern navigator.
  NavigatorState get parentNavigator => Navigator.of(context);

  /// Subpage navigator instance.
  /// It provides a subpage navigation pattern navigator.
  NavigatorState get subpageNavigator => _navigatorKey.currentState;
}

class _PageNavigatorStateWithoutBinding extends PageNavigatorState {
  @override
  RouteFactory get _onGenerateRoute => widget._pageRoutes;
}

class _PageNavigatorProvider extends ValueDelegateWidget<PageNavigatorState> {
  final Widget child;

  _PageNavigatorProvider({
    Key key,
    this.child,
    @required PageNavigatorState pageNavigatorState,
  }) : super(
          key: key,
          delegate: SingleValueDelegate<PageNavigatorState>(
            pageNavigatorState,
          ),
        );

  @override
  Widget build(BuildContext context) {
    return InheritedProvider<PageNavigatorState>(
      value: delegate.value,
      child: child,
    );
  }
}
